package com.itheima.d8_thread_pool;

import java.util.concurrent.*;

/**
 * 目标：掌握线程池的创建。
 *
 * 方式一：使用ExecutorService接口的实现类ThreadPoolExecutor自创建一个线程池对象。
 * 方式二：使用Executors（线程池的工具类）调用方法返回不同特点的线程池对象。
 *
 *  Executors:
 *          是一个线程池的工具类，提供了很多静态方法用于返回不同特点的线程池对象。
 *
 *              方法名称
 *  public static ExecutorService newFixedThreadPool (int nThreads)
 *  创建固定线程数量的线程池，如果某个线程因为执行异常而结束，那么线程池会补充一个新线程替代它。
 *
 *  public static ExecutorService newSingleThreadExecutor()
 *  创建只有一个线程的线程池对象，如果该线程出现异常而结束，那么线程池会补充一个新线程。
 *
 *  public static ExecutorService newCachedThreadPool()
 *  线程数量随着任务增加而增加，如果线程任务执行完毕且空闲了60s则会被回收掉。
 *
 *  public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize)
 *  创建一个线程池，可以实现在给定的延迟后运行任务，或者定期执行任务。
 *
 *  注意 ：这些方法的底层，都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象。
 *
 *  Executors使用可能存在的陷阱
 * 大型并发系统环境中使用Executors如果不注意可能会出现系统风险。
 */
public class ThreadPoolTest3 {
    public static void main(String[] args) throws Exception {
        // 1、通过ThreadPoolExecutor创建一个线程池对象。
//        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8,
//                TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
//                new ThreadPoolExecutor.CallerRunsPolicy());

        // 1-2 通过Executors创建一个线程池对象。
        /*
        源码：    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }           发现底层用的还是ThreadPoolExecutor
         */
        ExecutorService pool = Executors.newFixedThreadPool(17);  //16核+1
        // 老师：核心线程数量到底配置多少呢？？？
        // 计算密集型的任务：核心线程数量 = CPU的核数 + 1
        // IO密集型的任务：核心线程数量 = CPU核数 * 2

        // 2、使用线程处理Callable任务。
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());
    }
}
